/*
 * Copyright (c) 2010 Marc Poppleton
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.marcpoppleton.strawberry;

import java.text.DecimalFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.marcpoppleton.strawberry.R;
import org.marcpoppleton.strawberry.provider.Coc;
import org.marcpoppleton.strawberry.provider.Unit;
import org.marcpoppleton.strawberry.provider.PairedValue;
import org.marcpoppleton.strawberry.provider.PairedValuesFactory;
import org.marcpoppleton.strawberry.view.Slider;

import org.marcpoppleton.strawberry.constants.Preferences;
import org.marcpoppleton.strawberry.helper.DoFData;
import org.marcpoppleton.strawberry.helper.DoFHelper;

import android.app.Activity;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.SeekBar.OnSeekBarChangeListener;

public class StrawberryActivity extends Activity implements
		OnSeekBarChangeListener, OnItemSelectedListener {

	// Loging filter
	public static final String LOG = "strawberry";

	// Settings
	private SharedPreferences mPreferences;
	private Float coc;
	private int maxfocal;
	private Float dUnits;
	private String sUnits;
	private String sCamera;

	// DOF input
	private TextView mSelectedDistance;
	private Slider mFocalLength;
	private TextView mSelectedFocal;
	private Slider mDistance;
	private TextView mSelectedAperture;
	private TextView mSelectedCamera;
	private Slider mAperture;

	// DOF output
	private TextView mHyperfocal;
	private TextView mHyperfocalStart;
	private TextView mDofNear;
	private TextView mDofFar;
	private TextView mDofTotal;
	private TextView mDofInFront;
	private TextView mDofBehind;

	private PairedValue[] apertures;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.screen_main_relative);
		mPreferences = getSharedPreferences(Preferences.NAME, MODE_PRIVATE);
	}

	@Override
	public void onResume() {
		super.onResume();
		Log.d(LOG, "onResume");
		if (isFirstRun()) {
			SettingsActivity.show(this);
		} else {
			loadPrefs();
			setupViews();
		}
	}

	@Override
	public void onStart() {
		super.onStart();
		Log.d(LOG, "onStart");
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.menu, menu);
		return super.onCreateOptionsMenu(menu);
	}

	@Override
	public boolean onMenuItemSelected(int featureId, MenuItem item) {
		switch (item.getItemId()) {
		case R.id.menu_item_settings:
			SettingsActivity.show(this);
			return true;
		case R.id.menu_item_info:
			AboutActivity.showAbout(this);
			return true;
		case R.id.menu_item_help:
			HelpActivity.show(this);
			return true;
		}

		return super.onMenuItemSelected(featureId, item);
	}

	public void onProgressChanged(SeekBar seekBar, int progress,
			boolean fromTouch) {
		updateDisplayedUnits();
		if (!fromTouch)
			computeData();
	}

	public void onStartTrackingTouch(SeekBar seekBar) {
	}

	public void onStopTrackingTouch(SeekBar seekBar) {
		computeData();
	}

	public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
			long arg3) {
		updateDisplayedUnits();
		computeData();
	}

	public void onNothingSelected(AdapterView<?> arg0) {
	}

	private void setupViews() {

		apertures = PairedValuesFactory.getValues(this, R.xml.apertures);

		// outputs

		mHyperfocal = (TextView) findViewById(R.id.value_hyperfocal);
		mHyperfocalStart = (TextView) findViewById(R.id.value_hyperfocal_start);
		mDofNear = (TextView) findViewById(R.id.value_dofnear);
		mDofFar = (TextView) findViewById(R.id.value_doffar);
		mDofTotal = (TextView) findViewById(R.id.value_doftotal);
		mDofInFront = (TextView) findViewById(R.id.value_dofinfront);
		mDofBehind = (TextView) findViewById(R.id.value_dofbehind);

		// inputs

		mAperture = (Slider) findViewById(R.id.aperture);
		mAperture.setMax(apertures.length - 1);
		mAperture.setProgress((int) ((apertures.length - 1) / 2));
		mAperture.setOnSeekBarChangeListener(this);
		mFocalLength = (Slider) findViewById(R.id.focal);
		mFocalLength.setMax(maxfocal);
		mFocalLength.setOnSeekBarChangeListener(this);
		mDistance = (Slider) findViewById(R.id.distance);
		mDistance.setOnSeekBarChangeListener(this);
		mSelectedDistance = (TextView) findViewById(R.id.selected_distance);
		mSelectedFocal = (TextView) findViewById(R.id.selected_focal);
		mSelectedAperture = (TextView) findViewById(R.id.selected_aperture);
		mSelectedCamera = (TextView) findViewById(R.id.selected_camera);

		mAperture.setFocusable(true);
		mFocalLength.setFocusable(true);
		mDistance.setFocusable(true);
		updateDisplayedUnits();
		computeData();
	}

	private void updateDisplayedUnits() {
		Log.d(LOG, "updateDisplayedUnits");
		mSelectedDistance.setText(Integer.toString(mDistance.getProgress())
				+ " " + sUnits);
		mSelectedFocal.setText(Integer.toString(mFocalLength.getProgress())
				+ " mm");
		mSelectedAperture.setText(((PairedValue) apertures[mAperture
				.getProgress()]).getValue().toString());
		mSelectedCamera.setText(sCamera);
	}

	private boolean isFirstRun() {
		final String cameraId = mPreferences.getString(Preferences.KEY_CAMERA,Preferences.DEFAULT_CAMERA);
		final String unitId = mPreferences.getString(Preferences.KEY_UNITS,Preferences.DEFAULT_UNITS);
		// In previous version of the app units were not stored in database.
		// Default values for cameraId and unitId are -1
		// If cameraId and unitId are numeric, then it's the first time the app
		// is runned since install or upgrade
		final Pattern p = Pattern.compile("((-|\\+)?[0-9]+(\\.[0-9]+)?)+");
		final Matcher mCamera = p.matcher(cameraId);
		final Matcher mUnit = p.matcher(unitId);
		if (mCamera.matches() || mUnit.matches()) {
			return true;
		} else {
			return false;
		}
	}

	private void loadPrefs() {
		Log.d(LOG, "loading prefs");
		// loading max focal
		maxfocal = Integer.parseInt(mPreferences.getString(
				Preferences.KEY_MAXFOCAL, "400"));
		Log.d(LOG, "max focal stored in prefs is " + maxfocal);
		// loading camera and coc
		final String cameraId = mPreferences.getString(Preferences.KEY_CAMERA,
				Preferences.DEFAULT_CAMERA);
		final Cursor cCoc = this.managedQuery(Coc.CONTENT_URI,
				Coc.PROJECTION_IDS_AND_ALL, Coc._ID + " = '" + cameraId + "'",
				null, Coc.DEFAULT_SORT_ORDER);
		cCoc.moveToFirst();
		sCamera = cameraId;
		Log.d(LOG, "camera stored in prefs is " + sCamera);
		coc = cCoc.getFloat(cCoc.getColumnIndexOrThrow(Coc.VALUE));
		cCoc.close();
		Log.d(LOG, "coc stored in prefs is " + coc);
		// loading units
		final String unitId = mPreferences.getString(Preferences.KEY_UNITS,
				Preferences.DEFAULT_UNITS);
		sUnits = unitId;
		final Cursor cUnits = this.managedQuery(Unit.CONTENT_URI,
				Unit.PROJECTION_IDS_AND_ALL, Unit._ID + " = '" + unitId + "'",
				null, Unit.DEFAULT_SORT_ORDER);
		cUnits.moveToFirst();
		Log.d(LOG, "units stored in prefs is " + sUnits);
		dUnits = cUnits.getFloat(cUnits.getColumnIndexOrThrow(Unit.VALUE));
		cUnits.close();
		Log.d(LOG, "units stored in prefs is " + dUnits);
	}

	private void computeData() {
		final float focal = new Float(mFocalLength.getProgress());
		final float aperture = Float
				.parseFloat(((PairedValue) apertures[mAperture.getProgress()])
						.getKey().toString());
		final float distance = new Float(mDistance.getProgress());

		DoFData data = DoFHelper
				.compute(coc, focal, aperture, distance, dUnits);
		String mask = new String("#0.##");
		DecimalFormat dmf = new DecimalFormat(mask);

		mHyperfocal.setText(dmf.format(data.getHyperfocal()) + " " + sUnits);
		mHyperfocalStart.setText(dmf.format((data.getHyperfocal() / 2)) + " "
				+ sUnits);
		mDofNear.setText(dmf.format(data.getDofNear()) + " " + sUnits);
		mDofTotal.setText(dmf.format(data.getDofFar() - data.getDofNear())
				+ " " + sUnits);
		mDofInFront.setText(dmf.format(distance - data.getDofNear()) + " "
				+ sUnits);
		mDofBehind.setText(dmf.format(data.getDofFar() - distance) + " "
				+ sUnits);

		// We are closer than the infinite
		if (data.getDofFar() > 0.0) {
			mDofFar.setText(dmf.format(data.getDofFar()) + " " + sUnits);
		}
		// We are beyond the infinite, isn't that smart?
		else {
			mDofFar.setText(R.string.label_infinite);
			mDofTotal.setText(R.string.label_infinite);
			mDofBehind.setText(R.string.label_infinite);
		}
	}
}